#include "DevelopmentCard.h"

#include <cstdlib>
#include <ctime>

#include "CatanClassContractException.h"

namespace catan
{

/*static*/ std::vector<DevelopmentCard::Enum_DevelopmentCard> DevelopmentCard::vectorOfPossibleEnumValues;
/*static*/ std::vector<DevelopmentCard::Enum_DevelopmentCard> DevelopmentCard::vectorOfSortedEnumValues;
/*static*/ std::vector<DevelopmentCard::Enum_DevelopmentCard> DevelopmentCard::vectorOfShuffledEnumValues;

/*static*/ const std::vector<DevelopmentCard::Enum_DevelopmentCard> &DevelopmentCard::getVectorOfPossibleEnumValues()
{
	if (vectorOfPossibleEnumValues.empty())
	{
		vectorOfPossibleEnumValues.push_back(SOLDIER_CARD);
		vectorOfPossibleEnumValues.push_back(MONOPOLY_CARD);
		vectorOfPossibleEnumValues.push_back(ROAD_BUILDING_CARD);
		vectorOfPossibleEnumValues.push_back(YEAR_OF_PLENTY_CARD);
		vectorOfPossibleEnumValues.push_back(MARKET_CARD);
		vectorOfPossibleEnumValues.push_back(LIBRARY_CARD);
		vectorOfPossibleEnumValues.push_back(UNIVERSITY_CARD);
		vectorOfPossibleEnumValues.push_back(GOVERNORS_HOUSE_CARD);
		vectorOfPossibleEnumValues.push_back(CHAPEL_CARD);
	}
	return vectorOfPossibleEnumValues;
}

/*static*/ const std::vector<DevelopmentCard::Enum_DevelopmentCard> &DevelopmentCard::getVectorOfSortedEnumValues()
{
	if (vectorOfSortedEnumValues.empty())
	{
		for (int i=0; i<14; ++i) vectorOfSortedEnumValues.push_back(SOLDIER_CARD);
		for (int i=0; i<2; ++i) vectorOfSortedEnumValues.push_back(MONOPOLY_CARD);
		for (int i=0; i<2; ++i) vectorOfSortedEnumValues.push_back(ROAD_BUILDING_CARD);
		for (int i=0; i<2; ++i) vectorOfSortedEnumValues.push_back(YEAR_OF_PLENTY_CARD);
		vectorOfSortedEnumValues.push_back(MARKET_CARD);
		vectorOfSortedEnumValues.push_back(LIBRARY_CARD);
		vectorOfSortedEnumValues.push_back(UNIVERSITY_CARD);
		vectorOfSortedEnumValues.push_back(GOVERNORS_HOUSE_CARD);
		vectorOfSortedEnumValues.push_back(CHAPEL_CARD);
	}
	return vectorOfSortedEnumValues;
}

/*static*/ const std::vector<DevelopmentCard::Enum_DevelopmentCard> &DevelopmentCard::getVectorOfShuffledEnumValues()
{
	getVectorOfSortedEnumValues();
	if (vectorOfShuffledEnumValues.empty())
	{
		srand((int)time(0));
		for (std::vector<DevelopmentCard::Enum_DevelopmentCard>::const_iterator enumDevelopmentCardIterator = vectorOfSortedEnumValues.begin(); enumDevelopmentCardIterator != vectorOfSortedEnumValues.end(); ++enumDevelopmentCardIterator)
		{
			std::vector<DevelopmentCard::Enum_DevelopmentCard>::iterator enumDevelopmentCardInsertionPointIterator = vectorOfShuffledEnumValues.begin();
			int insertionPoint = rand()%(vectorOfShuffledEnumValues.size()+1);
			if (insertionPoint < static_cast<int>(vectorOfShuffledEnumValues.size()))
			{
				for (int i=0; i<insertionPoint; ++i)
				{
					enumDevelopmentCardInsertionPointIterator++;
				}
				vectorOfShuffledEnumValues.insert(enumDevelopmentCardInsertionPointIterator, *enumDevelopmentCardIterator);
			}
			else
			{
				vectorOfShuffledEnumValues.push_back(*enumDevelopmentCardIterator);
			}
		}
	}
	return vectorOfShuffledEnumValues;
}

/*static*/ bool DevelopmentCard::canInit(Enum_DevelopmentCard enumDevelopmentCard)
{
	const std::vector<DevelopmentCard::Enum_DevelopmentCard> enumValues = DevelopmentCard::getVectorOfPossibleEnumValues();
	for (std::vector<DevelopmentCard::Enum_DevelopmentCard>::const_iterator enumValueIterator = enumValues.begin(); enumValueIterator != enumValues.end(); ++enumValueIterator)
	{
		if (enumDevelopmentCard == *enumValueIterator)
		{
			return true;
		}
	}
	return false;
}

/*explicit*/ DevelopmentCard::DevelopmentCard(Enum_DevelopmentCard enumDevelopmentCard): enumDevelopmentCard(enumDevelopmentCard)
{
	if (!DevelopmentCard::canInit(enumDevelopmentCard))
	{
		throw CatanClassContractException(__FILE__, __LINE__, "DevelopmentCard::canInit(...) with constructor arguments should be true before creating instance.");
	}
}

DevelopmentCard::Enum_DevelopmentCard DevelopmentCard::getEnum() const
{
	return enumDevelopmentCard;
}

bool DevelopmentCard::operator==(const DevelopmentCard &other) const
{
	return enumDevelopmentCard == other.enumDevelopmentCard;
}

bool DevelopmentCard::operator<(const DevelopmentCard &other) const
{
	return enumDevelopmentCard < other.enumDevelopmentCard;
}

DevelopmentCard& DevelopmentCard::operator=(const DevelopmentCard& other)
{
    if (this != &other)
    {
        enumDevelopmentCard = other.enumDevelopmentCard;
    }
    return *this;	
}

}